#include "asio_thread.h"
#ifdef __linux__
#include <pthread.h>
#elif _WIN32
#include <windows.h>
#endif

namespace T_ASIO
{
    AsioThread::AsioThread()
        : work_guard_(asio::make_work_guard(io_context_)),
          state_(State::Ready),
          timer_(asio::steady_timer(io_context_))
    {}

    AsioThread::~AsioThread()
    {
        stop_thread();
        join();
    }

    bool AsioThread::start_thread(const std::string& name)
    {
        if (state_ != State::Ready) {
            return false;
        }
        state_ = State::Running;
        work_thread_ = std::make_unique<std::thread>(&AsioThread::thread_entry, this, name);
        return true;
    }

    void AsioThread::thread_entry(const std::string& name)
    {
        if (!name.empty()) {
            set_current_thread_name(name);
        }

        try {
            // 运行事件循环，这个调用会阻塞，直到io_context被stop或work_guard被reset
            io_context_.run();
        }
        catch (const std::exception& e) {
            std::cerr << "Exception caught in AsioThread " << get_id() << ": " << e.what() << std::endl;
        }
        catch (...) {
            std::cerr << "Unknown exception caught in AsioThread " << get_id() << std::endl;
        }

        state_ = State::Stopped;
    }

    void AsioThread::stop_thread()
    {
        if (state_ == State::Running) {
            // 重置 work_guard，允许 io_context::run() 在没有更多工作时退出
            work_guard_.reset();
            // 强行停止 io_context，使 run() 调用立即返回
            io_context_.stop();
        }
    }

    void AsioThread::join()
    {
        if (work_thread_ && work_thread_->joinable()) {
            work_thread_->join();
        }
        work_thread_.reset();
    }

    AsioThread::State AsioThread::get_state() const
    {
        return state_;
    }

    std::thread::id AsioThread::get_id() const
    {
        return work_thread_ ? work_thread_->get_id() : std::thread::id();
    }

    asio::io_context& AsioThread::get_io_context()
    {
        return io_context_;
    }

    asio::steady_timer& AsioThread::get_timer()
    {
        return timer_;
    }

    void AsioThread::set_current_thread_name(const std::string& name)
    {
        #ifdef __linux__
        pthread_setname_np(pthread_self(), name.substr(0, 15).c_str());
        #elif _WIN32
        std::wstring wname(name.begin(), name.end());
        SetThreadDescription(GetCurrentThread(), wname.c_str());
        #endif
    }

    uint64_t AsioThread::posix_time_s()
    {
        return std::chrono::time_point_cast<std::chrono::seconds>(std::chrono::system_clock::now()).time_since_epoch().count();
    }

    uint64_t AsioThread::posix_time_ms()
    {
        return std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
    }

    uint64_t AsioThread::posix_time_us()
    {
        return std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
    }

    uint64_t AsioThread::posix_time_ns()
    {
        return std::chrono::time_point_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
    }
}
